// ==UserScript==
// @name					Popup Search
// @author					lkytal
// @namespace				Lkytal
// @homepage				http://lkytal.github.io/
// @description				Popup search box and translate button (etc) for selected texts
// @include					*
// @exclude					*/test/index.html*
// @exclude					http://acid3.acidtests.org/*
// @exclude					http://www.acfun.tv/*
// @require					http://cdn.bootcss.com/jquery/3.1.0/jquery.min.js
// @version					3.3.1
// @icon					http://lkytal.qiniudn.com/ic.ico
// @grant					GM_xmlhttpRequest
// @grant					GM_addStyle
// @grant					unsafeWindow
// @grant					GM_openInTab
// @grant					GM_setClipboard
// @grant					GM_download
// @grant					GM_getValue
// @grant					GM_setValue
// @grant					GM_registerMenuCommand
// @charset					UTF-8
// @homepageURL				http://git.oschina.net/coldfire/GM
// @updateURL				https://git.oschina.net/coldfire/GM/raw/master/meta/popsearch.meta.js
// @downloadURL				https://git.oschina.net/coldfire/GM/raw/master/popsearch.user.js
// ==/UserScript==

"use strict";
var CopyText, GetOpt, InTextBox, Init, Load, OpenSet, SaveOpt, SetOpt, SettingWin, ShowBar, TimeOutHide, addCSS, fixPos, getLastRange, get_offsets_and_remove, get_selection_offsets, isChrome, log, popData, praseTranslation, praseTranslationMore,
  hasProp = {}.hasOwnProperty;

this.$ = this.jQuery = jQuery.noConflict(true);

popData = {
  count: 0,
  mouseIn: 0,
  bTrans: 0,
  text: ""
};

log = function(msg) {
  var text;
  popData.count += 1;
  text = "MsgId " + popData.count + " : " + msg;
  return console.log(text);
};

isChrome = function() {
  if ((typeof GM_download !== "undefined" && GM_download !== null) || navigator.userAgent.indexOf("Chrome") > -1) {
    return true;
  }
};

fixPos = function(sel, e) {
  var eventLeft, eventTop, fix, m_left, offsetLeft, offsetTop, offsets;
  offsets = get_selection_offsets(sel);
  offsetTop = offsets[0];
  offsetLeft = offsets[1];
  if (e != null) {
    if (isChrome()) {
      eventTop = e.pageY;
      eventLeft = e.pageX;
    } else {
      eventTop = e.pageY + document.body.scrollTop;
      eventLeft = e.pageX + document.body.scrollLeft;
      log(offsetTop + " : " + offsetLeft + " <==> " + eventTop + " : " + eventLeft);
      if (Math.abs(offsetTop - eventTop) > 120) {
        offsetTop = eventTop - 8;
      }
      if (Math.abs(offsetLeft - eventLeft) > 120) {
        offsetLeft = eventLeft + 10;
      }
    }
  } else {
    $('#showupbody').css('margin-left', '60px');
  }
  if (GetOpt('Dis_st')) {
    offsetTop = offsetTop - 2 - $('#ShowUpBox').height();
    if ((offsetTop - document.documentElement.scrollTop) < 40) {
      offsetTop = document.documentElement.scrollTop + 40;
    }
  } else {
    offsetTop += 1.1 * offsets[2];
  }
  m_left = $('#ShowUpBox').width();
  fix = 0;
  if (offsetLeft - m_left < 4) {
    fix = 4 - offsetLeft + m_left;
  }
  $('#ShowUpBox').css("top", offsetTop + "px").css("left", (offsetLeft - m_left + fix) + "px");
  return $('#popuptip').css('margin-left', m_left - 20 - fix);
};

$(document).mousedown(function(event) {
  if (popData.bTrans === 1) {
    Init();
  }
  return $('#ShowUpBox').hide();
});

TimeOutHide = function() {
  if (popData.mouseIn === 0 && GetOpt("Fade_st") && !popData.bTrans) {
    return $('#ShowUpBox').fadeOut(600);
  }
};

Init = function() {
  var $DivBox, UIList, id, opt;
  $('#ShowUpBox').remove();
  $('body').append("<span id=\"ShowUpBox\"> <span id=\"showupbody\"> <span id=\"popupwapper\" /> <span id=\"Gspan\" /> </span> </span>");
  $DivBox = $('#ShowUpBox');
  $DivBox.hide();
  $DivBox.on("mouseup", function(event) {
    event.stopPropagation();
    if (event.which === 3) {
      event.preventDefault();
      CopyText();
      $('#ShowUpBox').remove();
      Init();
      return false;
    } else if (event.which === 2) {
      event.preventDefault();
      return GM_openInTab(document.defaultView.getSelection().toString());
    }
  });
  $DivBox.on("contextmenu", function(event) {
    return false;
  });
  $DivBox.on("click mousedown dblclick mouseup", function(event) {
    return event.stopPropagation();
  });
  $DivBox.hover(function() {
    $(this).fadeTo(150, 1);
    return popData.mouseIn = 1;
  }, function() {
    if (!popData.bTrans) {
      $(this).fadeTo(300, 0.7);
      clearTimeout(popData.timer);
      popData.timer = setTimeout(TimeOutHide, 5500);
    }
    return popData.mouseIn = 0;
  });
  $('#popupwapper').append("<a id='gtrans' href=''><img title='translate' src='" + popData.tico + "' /></a> <a id='openurl' href=''><img title='Open Url' id='iconie' src='" + popData.ieIcon + "'/></a> <a id='sSite' href=''><img title='In Site Search' src='" + popData.inSite + "' /></a> <a id='sbaidu' href=''><img title='Baidu' src='" + popData.baiduico + "' /></a> <a id='sbing' href=''><img title='Bing' src='" + popData.bingico + "' /></a> <a id='sgoogle' href=''><img title='Google' id='gicon' src='" + popData.gicon + "' /></a>");
  $('#sgoogle, #sbing, #sbaidu, #openurl').on("click", function(e) {
    e.preventDefault();
    $('#ShowUpBox').hide();
    if (isChrome()) {
      return GM_openInTab($(this).attr('href'), {
        active: GetOpt("Focus_st") === 1
      });
    } else {
      return GM_openInTab($(this).attr('href'), !GetOpt("Focus_st"));
    }
  });
  UIList = {
    '#openurl': 'Open_st',
    '#sSite': 'Site_st',
    '#sbaidu': 'Baidu_st',
    '#sbing': 'Bing_st',
    '#sgoogle': 'Google_st'
  };
  for (id in UIList) {
    if (!hasProp.call(UIList, id)) continue;
    opt = UIList[id];
    if (!GetOpt(opt)) {
      $(id).hide();
    }
  }
  if (GetOpt('Tab_st')) {
    $DivBox.find('a').attr('target', '_blank');
  } else {
    $DivBox.find('a').attr('target', '_self');
  }
  $('#gtrans').on("click", function(event) {
    var callback;
    popData.bTrans = 1;
    $("#Gspan").empty().append("<div style='padding:10px;'><img src='" + popData.pending + "' /></div>").show();
    $('#popupwapper').hide();
    fixPos(document.defaultView.getSelection());
    callback = function(err) {
      console.log(err);
      return $('#Gspan').empty().append("Error:\n" + err).show();
    };
    if (popData.text.length < 380) {
      GM_xmlhttpRequest({
        method: 'GET',
        timeout: 3000,
        url: "http://fanyi.youdao.com/openapi.do?keyfrom=tinxing&key=1312427901&type=data&doctype=json&version=1.1&q=" + popData.text,
        onload: praseTranslation,
        onerror: callback,
        ontimeout: callback
      });
    } else {
      GM_xmlhttpRequest({
        method: 'GET',
        timeout: 3000,
        url: "http://fanyi.baidu.com/transapi?from=auto&to=auto&query=" + popData.text,
        onload: praseTranslationMore,
        onerror: callback,
        ontimeout: callback
      });
    }
    return event.preventDefault();
  });
  if (GetOpt('Dis_st')) {
    popData.tip = popData.tipup;
    return $DivBox.append('<span id="popuptip" class="tipup"></span>');
  } else {
    popData.tip = popData.tipdown;
    return $DivBox.prepend('<span id="popuptip" class="tipdown"></span>');
  }
};

praseTranslation = function(responseDetails) {
  var Result, Rline, Rst, Rtxt, i, j, len, len1, lines, ref, ref1;
  if (!popData.bTrans) {
    return;
  }
  Rtxt = JSON.parse(responseDetails.responseText);
  Rline = "";
  ref = Rtxt.translation;
  for (i = 0, len = ref.length; i < len; i++) {
    lines = ref[i];
    Rline += lines + "<br>";
  }
  Rst = "";
  if (Rtxt.basic != null) {
    ref1 = Rtxt.basic.explains;
    for (j = 0, len1 = ref1.length; j < len1; j++) {
      lines = ref1[j];
      Rst = lines + "<br>";
    }
  }
  Result = "<div id=\"tranRst\" style=\"font-size:13px;overflow:auto;padding:5px 15px;\"> <div style=\"line-height:160%;font-size:14px;padding:5px 0px;\">" + Rline + "</div> <p style=\"line-height:180%;font-size:13px;\"> " + Rst + " </p> </div>";
  $('#Gspan').empty().append(Result).show();
  fixPos(document.defaultView.getSelection());
};

praseTranslationMore = function(responseDetails) {
  var Result, Rline, Rtxt, i, len, lines, ref;
  if (!popData.bTrans) {
    return;
  }
  Rtxt = JSON.parse(responseDetails.responseText);
  Rline = "";
  ref = Rtxt.data;
  for (i = 0, len = ref.length; i < len; i++) {
    lines = ref[i];
    Rline += lines.dst + "<br>";
  }
  Result = "<div id=\"tranRst\" style=\"font-size:13px;overflow:auto;padding:5px 15px;\"> <p style=\"line-height:180%;font-size:13px;\"> " + Rline + " </p> </div>";
  $('#Gspan').empty().append(Result).show();
  fixPos(document.defaultView.getSelection());
};

InTextBox = function(selection) {
  var area, i, len, ref;
  ref = $('textarea, input[type=text], *[contenteditable="true"]', document);
  for (i = 0, len = ref.length; i < len; i++) {
    area = ref[i];
    if (selection.containsNode(area, true)) {
      return true;
    }
  }
  return false;
};

CopyText = function(seltxt) {
  var e;
  if (seltxt == null) {
    seltxt = document.defaultView.getSelection().toString();
  }
  log(seltxt);
  try {
    return GM_setClipboard(seltxt, "text");
  } catch (error) {
    e = error;
    if (GetOpt("Copy_st")) {
      alert("ERROR: Auto copying not supported and will be disabled now");
      SetOpt("Copy_st", 0);
    }
    return log("Copy Error: " + seltxt);
  }
};

$(document).on("mouseup", function(event) {
  if (event.which !== 1) {
    return;
  }
  if (GetOpt('Ctrl_st') && !event.ctrlKey) {
    return;
  }
  popData.lxe = event;
  return setTimeout(ShowBar, 10);
});

ShowBar = function(event) {
  var sel, seltxt;
  event = event != null ? event : popData.lxe;
  sel = document.defaultView.getSelection();
  seltxt = sel.toString();
  if (seltxt === '' || InTextBox(sel)) {
    return;
  }
  if (GetOpt("Copy_st")) {
    CopyText(seltxt);
  }
  popData.text = encodeURIComponent(seltxt);
  $('#Gspan').empty().hide();
  $('#sbaidu').attr('href', "https://www.baidu.com/s?wd=" + popData.text + "&ie=utf-8");
  $('#sbing').attr('href', "https://bing.com/search?q=" + popData.text + "&form=MOZSBR");
  $('#sgoogle').attr('href', "https://www.google.com/search?newwindow=1&safe=off&q=" + popData.text);
  $('#sSite').attr('href', "https://www.google.com/search?newwindow=1&safe=off&q=" + popData.text + "%20site:" + document.domain);
  if (seltxt.indexOf('http://') === -1) {
    $('#openurl').attr('href', "http://" + seltxt);
  } else {
    $('#openurl').attr('href', seltxt);
  }
  fixPos(sel, event);
  $('#ShowUpBox').css('opacity', 0.9).fadeIn(150);
  popData.mouseIn = 0;
  popData.bTrans = 0;
  clearTimeout(popData.timer);
  return popData.timer = setTimeout(TimeOutHide, 4000);
};

GetOpt = function(id) {
  return $("#" + id).data('val');
};

SetOpt = function(id) {
  var dom, val;
  dom = $("#" + id);
  val = GM_getValue(id);
  if (!val) {
    dom.addClass('close');
  }
  dom.data('val', val);
  return dom.click(function() {
    $(this).toggleClass('close');
    if ($(this).data('val') === 1) {
      return $(this).data('val', 0);
    } else {
      return $(this).data('val', 1);
    }
  });
};

SaveOpt = function(id) {
  return GM_setValue(id, $("#" + id).data('val'));
};

OpenSet = function() {
  if ($('#popup_setting_bg').length === 0) {
    SettingWin();
  }
  return $('#popup_setting_bg').fadeIn(400);
};

SettingWin = function() {
  var i, item, len, ref;
  if ($('#popup_setting_bg').length !== 0) {
    $('#popup_setting_bg').remove();
  }
  $("body").append('<div id="popup_setting_bg"> <div id="popup_setting_win"> <div id="popup_title">PopUp Search 设置</div> <div id="pop_st_wapper"> <div id="option_box"> <div id="rol1"> <span id="Google_st">Google搜索</span> <span id="Bing_st">Bing搜索</span> <span id="Baidu_st">Baidu搜索</span> </div> <div id="rol2"> <span id="Site_st">站内搜索按钮</span> <span id="Fade_st">超时自动隐藏</span> <span id="Dis_st">显示于文字上方</span> </div> <div id="rol3"> <span id="Tab_st">新标签页打开</span> <span id="Focus_st">前台标签页打开</span> <span id="Iframe_st">在Iframe中显示</span> </div> <div id="rol4"> <span id="Copy_st">自动复制选中文字</span> <span id="Open_st">打开选中文本按钮</span> <span id="Ctrl_st">仅按下Ctrl时显示</span> </div> </div> <br> <div id = "btnarea"> <div id="popup_tip">可在GreaseMonkey"用户脚本命令"菜单下的"Popup Search设置"打开此选项</div> <div id="popup_close" class="setting_btn">Close</div> <div id="popup_save" class="setting_btn">Save</div> </div> </div> </div> </div>');
  $("#rol1 > span, #rol2 > span, #rol3 > span, #rol4 > span").addClass("setting_sp_btn");
  ref = $("#popup_setting_win .setting_sp_btn");
  for (i = 0, len = ref.length; i < len; i++) {
    item = ref[i];
    if (item != null) {
      SetOpt(item.id);
    }
  }
  $("#popup_save").click(function() {
    var j, len1, ref1;
    ref1 = $("#popup_setting_win .setting_sp_btn");
    for (j = 0, len1 = ref1.length; j < len1; j++) {
      item = ref1[j];
      if (item != null) {
        SaveOpt(item.id);
      }
    }
    return $("#popup_setting_bg").fadeOut(300, function() {
      $("#popup_setting_bg").remove();
      SettingWin();
      $('#ShowUpBox').remove();
      return Init();
    });
  });
  $("#popup_close, #popup_setting_bg").click(function() {
    return $("#popup_setting_bg").fadeOut(300, function() {
      $("#popup_setting_bg").remove();
      return SettingWin();
    });
  });
  $('#popup_setting_win').click(function(e) {
    return e.stopPropagation();
  });
  return $('#popup_setting_bg').hide();
};

Load = function() {
  var UpdateAlert, popupmenu;
  if (window.self !== window.top || window.frameElement) {
    if (!GM_getValue("Iframe_st", 0)) {
      return;
    }
  }
  addCSS();
  UpdateAlert = GM_getValue("UpdateAlert", 0);
  if (UpdateAlert < 6) {
    GM_setValue("UpdateAlert", 6);
    GM_setValue("Open_st", GM_getValue("Open_st", 0));
    GM_setValue("Baidu_st", GM_getValue("Baidu_st", 1));
    GM_setValue("Bing_st", GM_getValue("Bing_st", 1));
    GM_setValue("Google_st", GM_getValue("Google_st", 1));
    GM_setValue("Fade_st", GM_getValue("Fade_st", 1));
    GM_setValue("Ctrl_st", GM_getValue("Ctrl_st", 0));
    GM_setValue("Dis_st", GM_getValue("Dis_st", 1));
    GM_setValue("Tab_st", GM_getValue("Tab_st", 1));
    GM_setValue("Focus_st", GM_getValue("Focus_st", 1));
    GM_setValue("Copy_st", GM_getValue("Copy_st", 0));
    GM_setValue("Site_st", GM_getValue("Site_st", 1));
    GM_setValue("Iframe_st", GM_getValue("Iframe_st", 0));
    OpenSet();
  } else {
    SettingWin();
  }
  Init();
  GM_registerMenuCommand("Popup Search设置", OpenSet, 'p');
  if (GM_getValue("PopupMenu", 0)) {
    popupmenu = document.body.appendChild(document.createElement("menu"));
    popupmenu.outerHTML = '<menu id="userscript-popup" type="context"><menuitem id="Popupset" label="Popup Search设置"></menuitem></menu>';
    document.querySelector("#Popupset").addEventListener("click", OpenSet, false);
    return $(document).on("contextmenu", function() {
      return document.body.setAttribute("contextmenu", "userscript-popup");
    });
  }
};

setTimeout(Load, 70);

addCSS = function() {
  popData.tipdown = "";
  popData.tipup = "";
  popData.baiduico = "";
  popData.bingico = "";
  popData.tico = "";
  popData.gicon = "";
  popData.ieIcon = "";
  popData.pending = "";
  popData.inSite = '';
  return GM_addStyle("#ShowUpBox{\n	all: unset; width: auto; height: auto; position: absolute; z-index: 102400000; display: inline-block;\n	line-height: 0; vertical-align: baseline; box-sizing: content-box;\n}\n#showupbody{\n	min-width: 20px; max-width: 750px; min-height: 20px; max-height: 500px; display: block;\n	border:solid 2px rgb(144,144,144); border-radius:1px; background:rgba(252, 252, 252, 1);\n}\n#popupwapper{\n	margin: 3px 2px 3.8px 2px; display:block; line-height: 0; font-size:0;\n}\n#Gspan{\n	line-height: normal; width: auto; font-size: 16px; overflow: auto; display: none;\n}\n#ShowUpBox img{\n	margin: 0px 2px; height: 22px; width: 22px; border-radius: 0px; padding: 0px; display: inline-block;\n	transition-duration: 0.1s; -moz-transition-duration: 0.1s; -webkit-transition-duration: 0.1s;\n}\n#ShowUpBox img:hover{\n	margin: -1px 1px -1px 1px; height: 24px; width: 24px;\n}\n#popuptip{\n	display:inline-block; clear:both; height:9px; width:9px;\n}\n.tipup {\n	background: url(" + popData.tipup + ") 0px 0px no-repeat transparent; margin-top: -2px; margin-bottom: 0px;\n}\n.tipdown {\n	background: url(" + popData.tipdown + ") 0px 0px no-repeat transparent; margin-top: 0px; margin-bottom: -2px;\n}\n#ShowUpBox a{\n	text-decoration: none; display:inline-block;\n}\n\n#popup_setting_bg {\n	all: unset; width: 100%; height: 100%; background: rgba(0, 0, 0, 0.2); position: fixed;\n	left: 0px; top: 0px; z-index:102400; display: none;\n}\n#popup_setting_win{\n	width:auto; text-align: justify; position:fixed; box-shadow:0 0 10px #222; z-index:102400;\n	box-sizing: content-box !important; background: rgba(255, 255, 255, 0.98);\n	font-family: \"Hiragino Sans GB\", \"Microsoft Yahei\", Arial, sans-serif;\n	left: -moz-calc(50% - 340px); left: -webkit-calc(50% - 340px); -moz-user-select:none;\n	top: -moz-calc(50% - 180px); top: -webkit-calc(50% - 180px); -webkit-user-select:none;\n}\n#pop_st_wapper{\n	padding:10px 40px 25px 40px;\n}\n#popup_title{\n	font-size:26px; text-align:center; padding: 20px;\n}\n#option_box { margin-right: -55px; }\n#popup_tip{\n	display:inline-block; font-size:11px; color:red; margin-top: 15px;\n}\n.setting_btn{\n	display:inline-block; font-size:16px; float: right; text-align: center; border: 2px solid #20CC66;\n	min-width: 45px; padding: 5px 10px 4px 10px; border-radius: 2px; margin: 0px 0px 0px 20px; color: #20CC66;\n}\n.setting_btn:hover { box-shadow: 0px 0px 1px #20CC66; }\n\n.setting_sp_btn{\n	min-width:150px; height:18px; font-size:12px; padding:4px; cursor:default; position:relative;\n	margin: 5px 55px 5px 0px; display:inline-block;\n}\n.setting_sp_btn:hover { box-shadow: 0px 0px 5px #DDD; background:#DDD; }\n.setting_sp_btn:active { box-shadow:0 0 3px #999 inset; }\n.setting_sp_btn::before{\n	position: absolute; right:0px; top:0px; content:\" \"; width:26px; height:26px; background: #6B4;\n	transition-duration: 0.2s; -moz-transition-duration: 0.2s; -webkit-transition-duration: 0.2s;\n}\n.setting_sp_btn.close { border:none; background:#DDD; }\n.setting_sp_btn.close::before { background:#C54; }");
};

getLastRange = function(selection) {
  var i, rangeNum, ref;
  for (rangeNum = i = ref = selection.rangeCount - 1; ref <= 0 ? i <= 0 : i >= 0; rangeNum = ref <= 0 ? ++i : --i) {
    if (!selection.getRangeAt(rangeNum).collapsed) {
      return selection.getRangeAt(rangeNum);
    }
  }
  return selection.getRangeAt(selection.rangeCount - 1);
};

get_offsets_and_remove = function($test_span) {
  var curr_elem, span_ht, span_wt, total_offsetLeft, total_offsetTop;
  curr_elem = $test_span[0];
  total_offsetTop = 0;
  total_offsetLeft = 0;
  while (curr_elem !== null) {
    total_offsetTop += curr_elem.offsetTop;
    total_offsetLeft += curr_elem.offsetLeft;
    curr_elem = curr_elem.offsetParent;
  }
  span_ht = $test_span.height();
  span_wt = $test_span.width();
  $test_span.remove();
  return [total_offsetTop, total_offsetLeft, span_ht, span_wt];
};

get_selection_offsets = function(selection) {
  var $test_span, lastRange, newRange;
  $test_span = $('<span style="display:inline;">x</span>');
  lastRange = getLastRange(selection);
  newRange = document.createRange();
  newRange.setStart(lastRange.endContainer, lastRange.endOffset);
  newRange.insertNode($test_span[0]);
  return get_offsets_and_remove($test_span);
};
